/*
 * @Author: hzm 
 * @Date: 2020-06-19 07:35:35 
 * @Last Modified by: hzm
 * @Last Modified time: 2020-06-19 10:23:58
 */

#include "EventLoop.h"
#include "MLogManager.h"

using namespace HeyIM;

EventLoop::EventLoop() {

    m_running.store(false);
    m_eventNotify.store(false);
    m_base = event_base_new();

    m_pipeEvent = std::make_shared<PipeEvent>(m_base, std::bind(&EventLoop::handlePendingFunc, this));
}

EventLoop::~EventLoop() {
    
    assert(!m_running.load());
    
    if(m_base != nullptr) {
        event_base_free(m_base);
        m_base = nullptr;
    }

    MLogInfo("EventLoop::~EventLoop");

}


bool EventLoop::run() {

    if(m_running.load()) {
        MLogError("EventLoop::run error: is running:{}", __LINE__);
        return false;
    }
    m_tid = std::this_thread::get_id();

    bool ret = m_pipeEvent -> start();
    if(!ret) {
        return false;
    }

    int ret2 = event_base_dispatch(m_base);
    if(ret2 != 0) {
        MLogError("EventLoop::run error:{}", ret2);
        return false;
    }

    m_running.store(true);
    
    MLogInfo("EventLoop::run sucessfully");

    return true;
}

void EventLoop::stop() {
    MLogInfo("EventLoop::stop");

    post(std::bind(&EventLoop::handleStop, this));
}

void EventLoop::handleStop() {
    MLogInfo("EventLoop::handleStop");

    auto f = [this]() {
        while(1) {
            handlePendingFunc();
            if(m_pendingFuncs.empty()) {
                break;
            }
        }
    };  

    f();
    
    m_running.store(false);
    event_base_loopexit(m_base, nullptr);

    f();
}

bool EventLoop::isRunning() const {
    return m_running.load();
}

bool EventLoop::isRunInLoopThread() const {
    return m_tid == std::this_thread::get_id();
}

void EventLoop::post(VoidParamHandler handler) {
    MLogInfo("EventLoop::post");
    
    {
        std::lock_guard<std::mutex> lock(m_pendingFuncsMutex);
        m_pendingFuncs.emplace_back(handler);
    }

    if(m_eventNotify.load()) { //已经通知过处理事件
        return;
    }

    if(m_pipeEvent && m_running.load()) {
        m_pipeEvent -> post();
    }
    m_eventNotify.store(false);
}

void EventLoop::handlePendingFunc() {
    MLogInfo("EventLoop::handlePendingFunc");

    std::vector<VoidParamHandler> funcs;
    {
        std::lock_guard<std::mutex> lock(m_pendingFuncsMutex);
        m_eventNotify.store(false);
        m_pendingFuncs.swap(funcs);
    }

    for(auto function: funcs) {
        function();
    }

}

event_base* EventLoop::eventBase() const {
    return m_base;
}
